#include "bsp_sw_iic1.h"

#define IIC1_TYPE GPIOC
#define IIC1_SDA_PIN GPIO_Pin_5 // SDA
#define IIC1_SCL_PIN GPIO_Pin_6 // SCL

uint8_t test_bit = 0;

void bsp_sw_iic1_init(void) // 引脚初始化 IO配置 PC5 - SDA  PC6 - SCL
{
    /* clk 配置 */
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); // 使能时钟

    /* gpio 配置 */
    GPIO_InitStructure.GPIO_Pin = IIC1_SDA_PIN | IIC1_SCL_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(IIC1_TYPE, &GPIO_InitStructure);

    GPIO_WriteBit(IIC1_TYPE, IIC1_SDA_PIN, Bit_SET); // 默认高电平
    GPIO_WriteBit(IIC1_TYPE, IIC1_SCL_PIN, Bit_SET);
}

/* void bsp_sda_config(io_config_t state) // SDA 输出/输入模式配置
{
    if (state == SDA_OUT)
    {
    }
    else
    {
    }
} */

// void bsp_iic1_wait(void) // 软件延时 30khz
// {
//     uint16_t bsp_iic1_wait_count = 50;
//     while (bsp_iic1_wait_count)
//     {
//         bsp_iic1_wait_count--;
//     }
// }
void bsp_iic1_scl_w(uint8_t w_bit) // 写SCL电平
{
    GPIO_WriteBit(IIC1_TYPE, IIC1_SCL_PIN, (BitAction)w_bit);
}
void bsp_iic1_sda_w(uint8_t w_bit) // 写SDA电平
{
    GPIO_WriteBit(IIC1_TYPE, IIC1_SDA_PIN, (BitAction)w_bit);
}
uint8_t bsp_iic1_sda_r(void) // 读SDA电平
{
    return GPIO_ReadInputDataBit(IIC1_TYPE, IIC1_SDA_PIN);
}
void bsp_iic1_stop(void) // 停止信号
{
    // bsp_sda_config(SDA_OUT);

    /* 先拉低SDA,以确保SCL为高电平时，拉高SDA产生停止信号 */
    bsp_iic1_scl_w(0);
    bsp_iic1_sda_w(0);

    /* SCL为高电平时，拉高SDA产生停止信号 */
    bsp_iic1_scl_w(1);
    bsp_iic1_sda_w(1);
}
uint8_t bsp_iic1_start(void) // IIC起始信号; 返回 1成功; 返回 0失败总线被占用
{
    // bsp_sda_config(SDA_OUT);

    /* IIC 总线释放，确保出现SCL高电平时，sda拉低 */
    bsp_iic1_scl_w(1);
    bsp_iic1_sda_w(1);

    if (bsp_iic1_sda_r() == 0) // 判断拉高SDA总线是否正常/被占用
    {
        printf("iic start error:iic sda can not pull up\n");
        bsp_iic1_stop();
        return 0;
    }

    bsp_iic1_sda_w(0); // 在SCL高电平期间，拉低SDA，产生起始信号
    // bsp_iic1_wait();

    if (bsp_iic1_sda_r() == 1) // 判断SDA总线是否正常
    {
        printf("iic start error:sda can not pull down\n");
        bsp_iic1_stop();
        return 0;
    }

    bsp_iic1_scl_w(0); // 钳住I2C总线，准备发送或接收数据

    return 1;
}
uint8_t bsp_iic_wait_ack(void) // ack应答接收及超时判断; 返回 1成功; 返回 0 ack应答超时
{
    uint16_t iic_wait_time = 0;

    // bsp_sda_config(SDA_IN);
    // bsp_iic1_wait();
    bsp_iic1_scl_w(1);
    // bsp_iic1_wait();

    while (GPIO_ReadInputDataBit(IIC1_TYPE, IIC1_SDA_PIN)) // 等待接收 ack应答
    {
        iic_wait_time++;
        if (iic_wait_time > 5000)
        {
            bsp_iic1_stop();
            // printf("bsp_iic_wait_ack error ! \n");
            return 0; // 接收 ack应答超时，返回 0
        }
    }
    bsp_iic1_scl_w(0); // 钳住I2C总线，准备发送或接收数据
    // bsp_iic1_scl_w(1);
    // bsp_iic1_wait();
    // bsp_sda_config(SDA_OUT);
    return 1; // 接收 ack应答成功，返回 1
}
void bsp_iic_send_byte(uint8_t byte) // 发送一个字节(uint8_t)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        bsp_iic1_sda_w(byte & (0x80 >> i)); // 掩码方式取出Byte的一个bit，并写入到SDA线
        bsp_iic1_scl_w(1);                  // 释放SCL，从机在此时读取SDA状态
        // bsp_iic1_wait();
        bsp_iic1_scl_w(0); // 拉低SCL，准备发送下一位数据
        // bsp_iic1_wait();
    }

    bsp_iic1_sda_w(1); // 释放sda
}

void bsp_iic_send_ack(uint8_t ack_bit) // 输入0产生 ack应答， 输入1产生 nack应答
{
    bsp_iic1_sda_w(ack_bit); // 主机把应答位数据放到SDA线
    bsp_iic1_scl_w(1);       // 释放SCL，从机在SCL高电平期间，读取应答位
    bsp_iic1_scl_w(0);       // 拉低SCL，开始下一个时序模块
    bsp_iic1_sda_w(1);
}
uint8_t bsp_iic_rece_byte(uint8_t ack_bit) // 返回读取的一个字节；输入 0产生ack应答， 输入 1产生nack应答
{
    uint8_t i;
    uint8_t byte = 0x00; // 定义接收的数据
    bsp_iic1_sda_w(1);   // 释放SDA,避免影响从机发送数据
    // bsp_sda_config(SDA_IN);
    for (i = 0; i < 8; i++)
    {
        bsp_iic1_scl_w(1); // 释放SCL，主机在SCL高电平期间读取SDA
        byte <<= 1;
        if (bsp_iic1_sda_r())
            byte++;
        // bsp_iic1_wait();
        bsp_iic1_scl_w(0); // 拉低SCL，从机在SCL低电平期间写入SDA
        // bsp_iic1_wait();
    }
    // bsp_sda_config(SDA_OUT);
    bsp_iic_send_ack(ack_bit); // 主机读数据给从机应答
    return byte;               // 返回接收到的一个字节数据
}

/* 应用函数 */
uint8_t bsp_iic_sw_send_data(uint8_t addr, uint8_t reg, uint8_t *send_buf, uint8_t len) // 连续发送数据
{
    uint8_t i;
    /* IIC起始信号 */
    if (bsp_iic1_start() == 0)
    {
        printf("iic send start error !\n");
        return 0;
    }

    /* 发送从机IIC地址 */
    bsp_iic_send_byte(addr << 1 | 0x00);
    if (bsp_iic_wait_ack() == 0)
    {
        printf("iic slave_addr ack error !\n");
        return 0;
    }

    /* 发送从机写寄存器地址 */
    bsp_iic_send_byte(reg);
    if (bsp_iic_wait_ack() == 0)
    {
        printf("iic send reg ack error !\n");
        return 0;
    }

    /* 发送数据 */
    for (i = 0; i < len; i++)
    {
        bsp_iic_send_byte(send_buf[i]);
        if (bsp_iic_wait_ack() == 0)
        {
            printf("iic send data ack error \n");
            return 0;
        }
    }

    /* iic停止信号 */
    bsp_iic1_stop();

    return 1;
}
uint8_t bsp_iic_sw_rece_data(uint8_t addr, uint8_t reg, uint16_t *rece_buf) // 连续接收数据
{
    /* IIC起始信号 */
    if (bsp_iic1_start() == 0)
    {
        printf("iic send start error !\n");
        return 0;
    }

    /* 发送从机IIC地址 */
    bsp_iic_send_byte(addr << 1 | 0x00); // 读数据最后1位为1
    if (bsp_iic_wait_ack() == 0)
    {
        printf("iic slave_addr ack error !\n");
        return 0;
    }

    /* 发送从机写寄存器地址 */
    bsp_iic_send_byte(reg);
    if (bsp_iic_wait_ack() == 0)
    {
        printf("iic send reg ack error !\n");
        return 0;
    }

    /* IIC起始信号 */
    if (bsp_iic1_start() == 0)
    {
        printf("iic send start error !\n");
        return 0;
    }

    /* 发送从机IIC地址 */
    bsp_iic_send_byte(addr << 1 | 0x01); // 读数据最后1位为1
    if (bsp_iic_wait_ack() == 0)
    {
        printf("iic slave_addr ack error !\n");
        return 0;
    }

    /* 接收从机数据 */
    *rece_buf = bsp_iic_rece_byte(0) << 8;
    *rece_buf |= bsp_iic_rece_byte(1); // 最后1个字节无应答

    /* iic停止信号 */
    bsp_iic1_stop();

    return 1;
}
